﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Sidvall.UI.Wpf.Controls
{
    public partial class RadioButtonListControl : UserControl
    {
        #region Public Members

        public event System.EventHandler<RoutedEventArgs> ButtonChecked;

        #region SelectedValue

        public static readonly System.Windows.DependencyProperty SelectedValueProperty = System.Windows.DependencyProperty.Register(nameof(SelectedValue), typeof(object), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedValuePropertyChanged, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public object SelectedValue
        {
            get
            {
                return GetValue(SelectedValueProperty);
            }
            set
            {
                SetValue(SelectedValueProperty, value);
            }
        }

        #endregion
        #region SelectedValuePath

        public static readonly System.Windows.DependencyProperty SelectedValuePathProperty = System.Windows.DependencyProperty.Register(nameof(SelectedValuePath), typeof(string), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string SelectedValuePath
        {
            get
            {
                return GetValue(SelectedValuePathProperty) as string;
            }
            set
            {
                SetValue(SelectedValuePathProperty, value);
            }
        }

        #endregion
        #region DisplayMemberPath

        public static readonly System.Windows.DependencyProperty DisplayMemberPathProperty = System.Windows.DependencyProperty.Register(nameof(DisplayMemberPath), typeof(string), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string DisplayMemberPath
        {
            get
            {
                return GetValue(DisplayMemberPathProperty) as string;
            }
            set
            {
                SetValue(DisplayMemberPathProperty, value);
            }
        }

        #endregion
        #region GroupName

        public static readonly System.Windows.DependencyProperty GroupNameProperty = System.Windows.DependencyProperty.Register(nameof(GroupName), typeof(string), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string GroupName
        {
            get
            {
                return GetValue(GroupNameProperty) as string;
            }
            set
            {
                SetValue(GroupNameProperty, value);
            }
        }

        #endregion
        #region ItemsSource

        public static readonly System.Windows.DependencyProperty ItemsSourceProperty = System.Windows.DependencyProperty.Register(nameof(ItemsSource), typeof(System.Collections.IEnumerable), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, OnItemsSourcePropertyChanged, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public System.Collections.IEnumerable ItemsSource
        {
            get
            {
                return GetValue(ItemsSourceProperty) as System.Collections.IEnumerable;
            }
            set
            {
                SetValue(ItemsSourceProperty, value);
            }
        }

        #endregion
        #region ItemMargin

        public static readonly System.Windows.DependencyProperty ButtonMarginProperty = System.Windows.DependencyProperty.Register(nameof(ItemMargin), typeof(Thickness), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(new Thickness(8, 0, 0, 0), System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public Thickness ItemMargin
        {
            get
            {
                return (Thickness)GetValue(ButtonMarginProperty);
            }
            set
            {
                SetValue(ButtonMarginProperty, value);
            }
        }

        #endregion
        #region ItemOrientation

        public static readonly System.Windows.DependencyProperty ItemOrientationProperty = System.Windows.DependencyProperty.Register(nameof(ItemOrientation), typeof(System.Windows.Controls.Orientation), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(System.Windows.Controls.Orientation.Vertical, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public System.Windows.Controls.Orientation ItemOrientation
        {
            get
            {
                return (System.Windows.Controls.Orientation)GetValue(ItemOrientationProperty);
            }
            set
            {
                SetValue(ItemOrientationProperty, value);
            }
        }

        #endregion
        #region LabelMargin

        public static readonly System.Windows.DependencyProperty LabelMarginProperty = System.Windows.DependencyProperty.Register(nameof(LabelMargin), typeof(Thickness), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(new Thickness(0, 0, 0, 0), System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public Thickness LabelMargin
        {
            get
            {
                return (Thickness)GetValue(LabelMarginProperty);
            }
            set
            {
                SetValue(LabelMarginProperty, value);
            }
        }

        #endregion
        #region LabelText

        public static readonly System.Windows.DependencyProperty LabelTextProperty = System.Windows.DependencyProperty.Register(nameof(LabelText), typeof(string), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, OnLabelTextPropertyChanged, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public string LabelText
        {
            get
            {
                return GetValue(LabelTextProperty) as string;
            }
            set
            {
                SetValue(LabelTextProperty, value);
            }
        }

        #endregion
        #region LabelLeftContent

        public static readonly System.Windows.DependencyProperty LabelLeftContentProperty = System.Windows.DependencyProperty.Register(nameof(LabelLeftContent), typeof(object), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public object LabelLeftContent
        {
            get
            {
                return GetValue(LabelLeftContentProperty);
            }
            set
            {
                SetValue(LabelLeftContentProperty, value);
            }
        }

        #endregion
        #region LabelRightContent

        public static readonly System.Windows.DependencyProperty LabelRightContentProperty = System.Windows.DependencyProperty.Register(nameof(LabelRightContent), typeof(object), typeof(RadioButtonListControl),
            new System.Windows.FrameworkPropertyMetadata(null, System.Windows.FrameworkPropertyMetadataOptions.None, null, null, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
        public object LabelRightContent
        {
            get
            {
                return GetValue(LabelRightContentProperty);
            }
            set
            {
                SetValue(LabelRightContentProperty, value);
            }
        }

        #endregion

        #endregion
        #region Private Members

        private bool EventsEnabled = true;

        #region InitializeLabel

        private static void InitializeLabel(RadioButtonListControl parent)
        {
            if (string.IsNullOrEmpty(parent.LabelText))
            {
                parent.Label.Visibility = Visibility.Collapsed;
            }
            else
            {
                parent.Label.Visibility = Visibility.Visible;
            }
        }

        #endregion

        #region OnItemsSourcePropertyChanged

        private static void OnItemsSourcePropertyChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)
        {
            var parent = d as RadioButtonListControl;
            if (parent == null)
                return;

            parent.StackPanel.Children.Clear();
            if (parent.ItemsSource != null)
            {
                var count = 0;
                foreach (var item in parent.ItemsSource)
                {
                    var radioButton = new RadioButton()
                    {
                        GroupName = parent.GroupName,
                        Content = Sidvall.SystemContext.Current.CodeManager.GetPropertyValue(item, parent.DisplayMemberPath),
                        Tag = Sidvall.SystemContext.Current.CodeManager.GetPropertyValue(item, parent.SelectedValuePath),
                    };
                    if (count > 0)
                        radioButton.Margin = parent.ItemMargin;
                    if (radioButton.Tag.Equals(parent.SelectedValue))
                        radioButton.IsChecked = true;
                    parent.StackPanel.Children.Add(radioButton);
                    count += 1;
                }
            }
        }

        #endregion
        #region OnLabelTextPropertyChanged

        private static void OnLabelTextPropertyChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)
        {
            var parent = d as RadioButtonListControl;
            if (parent == null)
                return;
            InitializeLabel(parent);
        }

        #endregion
        #region OnSelectedValuePropertyChanged

        private static void OnSelectedValuePropertyChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)
        {
            var parent = d as RadioButtonListControl;
            if (parent == null)
                return;

            parent.EventsEnabled = false;
            if (parent.StackPanel.Children != null)
            {
                foreach (var item in parent.StackPanel.Children)
                {
                    var radioButton = item as RadioButton;
                    if (radioButton != null)
                    {
                        if (radioButton.Tag == null)
                            radioButton.IsChecked = false;
                        else if (parent.SelectedValue == null)
                            radioButton.IsChecked = false;
                        else if (radioButton.Tag.Equals(parent.SelectedValue))
                            radioButton.IsChecked = true;
                        else
                            radioButton.IsChecked = false;
                    }
                }
            }
            parent.EventsEnabled = true;
        }

        #endregion

        #endregion
        #region Events

        #region OnButtonChecked

        private void OnButtonChecked(object sender, RoutedEventArgs e)
        {
            if (!this.EventsEnabled)
                return;
            var radioButton = e.Source as RadioButton;
            if (radioButton == null)
                return;
            this.SelectedValue = radioButton.Tag;
            if (this.ButtonChecked != null)
                this.ButtonChecked.Invoke(sender, e);
        }

        #endregion

        #endregion
        #region Constructors

        public RadioButtonListControl()
        {
            InitializeComponent();

            this.StackPanel.AddHandler(ToggleButton.CheckedEvent, new RoutedEventHandler(OnButtonChecked));
        }

        #endregion
    }
}
